package com.idanchuang.count.service.impl

import com.idanchuang.count.config.IntegrationTestConfig
import com.idanchuang.count.service.UserCountService
import com.idanchuang.user.count.service.api.request.command.count.*
import com.idanchuang.user.count.service.api.request.query.count.UserCountBatchQuery
import com.idanchuang.user.count.service.api.request.query.count.UserCountQuery
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.StringRedisTemplate
import org.springframework.test.context.ContextConfiguration
import org.testcontainers.spock.Testcontainers
import spock.lang.Specification

/**
 * @author Richard_yyf* @version 1.0 2021/6/8
 */
@ContextConfiguration(
        initializers = IntegrationTestConfig.IntegrationTestInitializer.class,
        classes = [IntegrationTestConfig.class])
@Testcontainers
class UserCountServiceImplTest extends Specification {

    @Autowired
    private StringRedisTemplate stringRedisTemplate

    static def bizCode = "bizA"

    def cleanup() {
        // runs after every feature method
        // clean
        Set<String> keys = stringRedisTemplate.keys("msg::*")
        keys.addAll(stringRedisTemplate.keys("count:*"))
        keys.addAll(stringRedisTemplate.keys("rt:*"))
        println("delete keys: " + keys.toString())
        stringRedisTemplate.delete(keys)
    }

    @Autowired
    private UserCountService userCountService

    def "test_batchReset"() {
        given:
        UserMultiScenesCountResetCommand command1 = new UserMultiScenesCountResetCommand(
                userCode: 100,
                bizCode: bizCode,
                sceneCountResetList: [new SceneCountReset(scene: "sceneA", count: 5),
                                      new SceneCountReset(scene: "sceneB", count: 3)]
        )

        UserMultiScenesCountResetCommand command2 = new UserMultiScenesCountResetCommand(
                userCode: 101,
                bizCode: bizCode,
                sceneCountResetList: [new SceneCountReset(scene: "sceneA", count: 5),
                                      new SceneCountReset(scene: "sceneB", count: 3)]
        )

        when:
        userCountService.batchResetCount([command1, command2])

        then:
        5 == userCountService.query(new UserCountQuery(scene: "sceneA", userCode: 100, bizCode: bizCode)).count
        3 == userCountService.query(new UserCountQuery(scene: "sceneB", userCode: 100, bizCode: bizCode)).count
        5 == userCountService.query(new UserCountQuery(scene: "sceneA", userCode: 101, bizCode: bizCode)).count
        3 == userCountService.query(new UserCountQuery(scene: "sceneB", userCode: 101, bizCode: bizCode)).count
    }

    def "test_Query"() {
        given:
        def userCode = 100
        def scene = "sceneA"

        def command = new UserSceneCountUpdateCommand()
        command.bizCode = bizCode
        command.userCode = userCode
        command.sceneCountIncrement = new SceneCountIncrement(
                scene: scene,
                incrementAmount: 5
        )

        when:
        userCountService.count(Collections.singletonList(command))
        def queryRet = userCountService.query(new UserCountQuery(
                scene: scene,
                userCode: userCode,
                bizCode: bizCode
        ))

        then:
        queryRet != null
        queryRet.userCode == userCode
        queryRet.scene == scene
        queryRet.count == command.sceneCountIncrement.incrementAmount
    }

    def "test_AsyncCountInBatch_And_BatchQuery"() {
        given:
        def userCode = 100
        def scene1 = "sceneA"
        def scene2 = "sceneB"

        def command1 = new UserSceneCountUpdateCommand(
                bizCode: bizCode,
                userCode: userCode,
                sceneCountIncrement: new SceneCountIncrement(scene: scene1, incrementAmount: 5)
        )

        def command2 = new UserSceneCountUpdateCommand(
                bizCode: bizCode,
                userCode: userCode,
                sceneCountIncrement: new SceneCountIncrement(scene: scene2, incrementAmount: 2)
        )

        when:
        userCountService.count([command1, command2])
        def queryRet = userCountService.batchQuery(new UserCountBatchQuery(
                userCode: userCode,
                sceneList: [scene1, scene2, "notExist"],
                bizCode: bizCode
        ))

        then:
        // assert all data right
        queryRet != null
        queryRet.userCode == userCode
        queryRet.scenesCountMap.get("notExist") == null
        queryRet.scenesCountMap.get(scene1) == command1.sceneCountIncrement.incrementAmount
        queryRet.scenesCountMap.get(scene2) == command2.sceneCountIncrement.incrementAmount
    }

    def "test_AsyncMultiCountInBatch"() {
        given:
        def userCode = 100
        def scene1 = "sceneA"
        def scene2 = "sceneB"

        def command1 = new UserMultiScenesCountUpdateCommand(
                bizCode : bizCode,
                userCode : userCode,
                sceneCountIncrements : [
                        new SceneCountIncrement(scene: scene1, incrementAmount: 5),
                        new SceneCountIncrement(scene: scene1, incrementAmount: 5)
                ]
        )

        def command2 = new UserMultiScenesCountUpdateCommand(
                bizCode : bizCode,
                userCode : userCode,
                sceneCountIncrements : [
                        new SceneCountIncrement(scene: scene2, incrementAmount: 3),
                        new SceneCountIncrement(scene: scene2, incrementAmount: 3)
                ]
        )


        when:
        userCountService.multiCount([command1, command2])
        def queryRet = userCountService.batchQuery(new UserCountBatchQuery(
                userCode: userCode,
                sceneList: [scene1, scene2],
                bizCode: bizCode
        ))

        then:
        queryRet != null
        queryRet.userCode == userCode
        queryRet.scenesCountMap.get(scene1) == 10
        queryRet.scenesCountMap.get(scene2) == 6
    }

}
